package com.health.trans.util;

import cn.hutool.cache.Cache;
import cn.hutool.cache.CacheUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.health.trans.common.util.GenericUtil;
import com.health.trans.pojo.TableInfo;
import com.health.trans.pojo.TransParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.WordUtils;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.persistence.Table;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author nqlz
 */
@Slf4j
@Component
public class EntityOperations {

    public static Set<Class<?>> POJO_CLASSES;
    public static Set<String> packageNames;

    @PostConstruct
    public void init() {
        if (CollUtil.isEmpty(packageNames)) {
            throw new RuntimeException("未添加实体包名。");
        }
        initPojoClasses();
    }

    public static void initPojoClasses() {
        POJO_CLASSES = packageNames.stream()
                .map(ClassUtil::scanPackage)
                .flatMap(Set::stream)
                .filter(i -> i.isAnnotationPresent(Table.class)).collect(Collectors.toSet());
    }

    private static final Cache<String, Class<?>> CLASS_CACHE = CacheUtil.newLRUCache(200);

    private static final String TB_ = "tb_";


    public static <T> Class<T> getPojoClass(String tableName) {
        if (CollUtil.isEmpty(POJO_CLASSES)) {
            initPojoClasses();
        }
        if (CLASS_CACHE.containsKey(tableName) && null != CLASS_CACHE.get(tableName)) {
            return GenericUtil.get(CLASS_CACHE.get(tableName));
        }
        Class<?> aClass = CLASS_CACHE.get(tableName, () -> {
            String[] tableKeys = getTableKeys(tableName);
            Optional<Class<?>> tableClass = POJO_CLASSES.parallelStream()
                    .filter(i -> StrUtil.equalsAnyIgnoreCase(i.getSimpleName(), tableKeys))
                    .filter(i -> i.isAnnotationPresent(Table.class))
                    .findFirst();
            if (tableClass.isPresent()) {
                for (String tableKey : tableKeys) {
                    CLASS_CACHE.put(tableKey, tableClass.get());
                }
                return tableClass.get();
            }
            return null;
        });
        return GenericUtil.get(aClass);
    }

    private static String[] getTableKeys(String tableName) {
        List<String> values = new ArrayList<>();
        if (StrUtil.startWithIgnoreCase(tableName, TB_)) {
            String replace = tableName.replace(TB_, "");
            values.add(replace);
            values.add(StrUtil.toCamelCase(replace));
        }
        values.add(tableName);
        return ArrayUtil.toArray(values, String.class);
    }

    public static <T, J, R extends JpaRepository<T, J> & JpaSpecificationExecutor<T>> R getRepositoryByClass(Class<?> clazz) {
        R repository = null;
        try {
            repository = SpringUtil.getBean(WordUtils.uncapitalize(clazz.getSimpleName()) + "Repository");
        } catch (Exception e) {
            log.error("没有{}对应的repository", clazz.getSimpleName());
        }
        return repository;
    }

}
